<?php
/**
 * 常用操作
 * 
 * @author ShuangYa
 * @package APIGateway
 * @category Library
 * @link https://www.sylingd.com/
 * @copyright Copyright (c) 2018 ShuangYa
 * @license https://www.sylibs.com/go/apigateway/license
 */
namespace ag\library;

use yesf\Yesf;
use yesf\library\Plugin;
use yesf\library\Swoole;
use APIGateway\Protobuf\Response;
use APIGateway\Protobuf\Response\Code;
use Google\Protobuf\Internal\Message;

class Utils {
	/**
	 * 格式化WebAPI的返回结果
	 * 
	 * @access public
	 * @param array $result
	 * @return string
	 */
	public static function getWebApiResult($result = []) {
		if (isset($result['error'])) {
			return json_encode([
				'success' => FALSE,
				'error' => $result['error']
			]);
		} else {
			$result['success'] = TRUE;
			return json_encode($result);
		}
	}
	/**
	 * 将结果转化为JSON
	 * 
	 * @access public
	 * @param APIGateway\Protobuf\Response $rs
	 * @return string
	 */
	public static function toJSON($rs = NULL) {
		if ($rs instanceof Response) {
			$result = $rs;
		} else {
			$result = Dispatcher::createResult(Dispatcher::CODE_SUCCESS, "");
		}
		return $result->serializeToJsonString();
	}
	/**
	 * 生成UUID
	 * 
	 * @access public
	 * @param int $length
	 * @return string
	 */
	public static function generateUniqueId($length = 24) {
		static $i = 0;
		$i == 0 && $i = mt_rand(1, 0x7FFFFF);
		$r = sprintf('%08x%06x%04x%06x',
			//4-byte value representing the seconds since the Unix epoch
			time() & 0xFFFFFFFF,
			//3-byte machine identifier
			crc32(substr((string)gethostname(), 0, 256)) >> 8 & 0xFFFFFF,
			//2-byte process id
			Swoole::getSwoole()->worker_pid & 0xFFFF,
			//3-byte counter, starting with a random value
			$i = $i > 0xFFFFFE ? 1 : $i + 1
		);
		// if length is more than 24, append some random words
		while (strlen($r) < $length) {
			$r .= ord(mt_rand(65, 90) + (mt_rand(0, 1) === 1 ? 32 : 0));
		}
		return $r;
	}
	/**
	 * 将Protobuf的Message转为Array
	 * 
	 * @access public
	 * @param object $message
	 * @return array
	 */
	public static function messageToArray($message): array {
		$data = [];
		if (!($message instanceof Message)) {
			return $data;
		}
		$methods = get_class_methods($message);
		foreach ($methods as $m) {
			if (strpos($m, 'get') === 0) {
				$name = lcfirst(substr($m, 3));
				$v = $message->$m();
				if ($v instanceof Message) {
					$data[$name] = self::messageToArray($v);
				} else {
					$data[$name] = $v;
				}
			}
		}
		return $data;
	}
	public static function getHttp($info, $before = NULL, $isDefer = FALSE) {
		if (isset($info['module'])) {
			$cookie = Cache::exists('cookie_' . $info['uuid']) ? swoole_unserialize(Cache::get('cookie_' . $info['uuid'])) : [];
		} else {
			$cookie = [];
		}
		$ip = isset($info['ip']) ? $info['ip'] : \Swoole\Coroutine::gethostbyname($info['domain']);
		$client = new \Swoole\Coroutine\Http\Client($ip, isset($info['port']) ? $info['port'] : 80);
		//生成Cookie字符串
		if (count($cookie[$info['module']]) > 0) {
			$cookie_str = '';
			foreach ($cookie[$info['module']] as $k => $v) {
				$cookie_str .= $k . '=' . $v . '; ';
			}
			$cookie_str = substr($cookie_str, 0, strlen($cookie_str) - 2);
		} else {
			$cookie_str = '';
		}
		$header = [
			'Host' => $info['domain'],
			'User-Agent' => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:51.0) Gecko/20100101 Firefox/51.0 APIGateway/1.0',
			'Cookie' => $cookie_str
		];
		if (isset($info['header'])) {
			$header = array_merge($header, $info['header']);
		}
		$client->setHeaders($header);
		if (is_callable($before)) {
			$before($client);
		}
		//是否等待返回
		if ($isDefer) {
			$client->setDefer();
		}
		//POST请求
		if (isset($info['post'])) {
			$result = $client->post($info['path'], $info['post']);
		} else {
			$result = $client->get($info['path']);
		}
		if ($result === FALSE) {
			throw new \Exception('connect failed');
		}
		if ($isDefer) {
			return $client;
		}
		//保存Cookie
		if (isset($info['module']) && is_array($client->set_cookie_headers)) {
			foreach ($result->set_cookie_headers as $k => $v) {
				$dh = strpos($v, '=');
				$fh = strpos($v, ';');
				$cookie[$info['module']][$k] = ($dh === FALSE ? $v : ($fh === FALSE ? substr($v, ++$dh) : substr($v, ++$dh, $fh - $dh)));
			}
			Cache::set('cookie_' . $info['uuid'], swoole_serialize($cookie));
		}
		$client->close();
		return $client->body;
	}
}